home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / fractal / frasr182 / encoder.c < prev    next >
C/C++ Source or Header  |  1993-08-02  |  29KB  |  880 lines

  1. /*
  2.     encoder.c - GIF Encoder and associated routines
  3.     This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
  4. */
  5.  
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #ifndef XFRACT
  10. #include <io.h>
  11. #endif
  12. #include "fractint.h"
  13. #include "fractype.h"
  14. #include "prototyp.h"
  15.  
  16. /* MCP 10-27-91 */
  17. #ifdef WINFRACT
  18.    extern int OperCancelled;
  19.    void OpenStatusBox(void);
  20.    void UpdateStatusBox(unsigned long Partial, unsigned long Total);
  21.    void CloseStatusBox(void);
  22. #endif
  23.  
  24. extern char s_cantopen[];
  25. extern char s_cantwrite[];
  26. extern char s_cantcreate[];
  27. extern char s_cantunderstand[];
  28. extern char s_cantfind[];
  29. extern char maxfn;
  30. static void _fastcall setup_save_info(struct fractal_info *);
  31. static int inittable(void);
  32. static int _fastcall shftwrite(BYTE *color,int numcolors);
  33. static int _fastcall raster(unsigned int);
  34. static int  _fastcall extend_blk_len(int datalen);
  35. static int _fastcall put_extend_blk(int block_id,int block_len,char far *block_data);
  36. static int  _fastcall store_item_name(char *);
  37.  
  38. extern int initbatch;
  39. extern char far *resume_info;        /* pointer to resume info if allocated */
  40. extern int  resume_len;         /* length of resume info */
  41. extern char LName[];
  42. extern char FormName[];         /* formula name */
  43. extern char IFSName[];
  44. extern int  active_system;        /* 0=dos, 1=windows */
  45. extern int  far *ranges;
  46. extern int  rangeslen;
  47.  
  48. extern    int    sxdots,sydots;        /* # of dots on the physical screen    */
  49. extern    int    sxoffs,syoffs;        /* physical top left of logical screen */
  50. extern    int    xdots, ydots;        /* # of dots on the logical screen     */
  51. extern    int    viewwindow;        /* 0 for full screen, 1 for window */
  52. extern    float    finalaspectratio;    /* for view shape and rotation */
  53. extern    int    viewxdots,viewydots;    /* explicit view sizing */
  54. extern    int    colors;         /* maximum colors available */
  55. extern    int    dotmode;        /* so we can detect disk-video */
  56. extern    char overwrite;         /* overwrite on/off */
  57. extern    int    resave_flag;        /* resaving after a timed save */
  58. extern    int    started_resaves;
  59. extern    int    timedsave;        /* if doing an auto save */
  60. extern    int    disk16bit;        /* 16 bit continuous potential */
  61.  
  62. extern BYTE dacbox[256][3];    /* Video-DAC (filled in by SETVIDEO) */
  63. extern    int    gotrealdac;        /* DAC valid? */
  64. extern int    daclearn, daccount;    /* used by the color-cyclers */
  65. extern SEGTYPE    extraseg;        /* used by Save-to-GIF routines */
  66. extern int    debugflag;
  67.  
  68. extern int    gif87a_flag;        /* if 1, supress GIF extension blocks */
  69.  
  70. extern int    calc_status;
  71. extern long   calctime;
  72. extern char   stdcalcmode;
  73. extern int    fractype;
  74. extern double xxmin,xxmax;
  75. extern double yymin,yymax;
  76. extern double xx3rd,yy3rd;
  77. extern double param[];
  78. extern int    major_method;        /* inverse julia parms */
  79. extern int    minor_method;
  80. extern int    maxit;            /* try this many iterations */
  81. extern int    fillcolor;        /* fill color: -1 = normal  */
  82. extern int    inside;            /* inside color: 1=blue     */
  83. extern int    outside;            /* outside color, if set    */
  84. extern int    finattract;        /* finite attractor option  */
  85. extern int    forcesymmetry;
  86. extern int    LogFlag;            /* non-zero if logarithmic palettes */
  87. extern int    rflag, rseed;
  88. extern int    periodicitycheck;
  89. extern char   useinitorbit;
  90. extern _CMPLX initorbit;
  91. extern int    pot16bit;
  92. extern float  finalaspectratio;
  93. extern double potparam[3];        /* three potential parameters*/
  94. extern double inversion[];
  95. extern int    decomp[];
  96. extern int    distest;            /* non-zero if distance estimator   */
  97. extern int    distestwidth;
  98. extern int    init3d[20];        /* '3d=nn/nn/nn/...' values */
  99. extern char   floatflag;        /* floating-point fractals? */
  100. extern int    usr_biomorph;
  101. extern int    bailout;            /* user input bailout value */
  102. extern int    previewfactor;
  103. extern int    xtrans;
  104. extern int    ytrans;
  105. extern int    red_crop_left;
  106. extern int    red_crop_right;
  107. extern int    blue_crop_left;
  108. extern int    blue_crop_right;
  109. extern int    red_bright;
  110. extern int    blue_bright;
  111. extern int    xadjust;
  112. extern int    eyeseparation;
  113. extern int    glassestype;
  114. extern int    save_system;
  115. extern int    save_release;
  116. extern int    display3d;        /* 3D display flag: 0 = OFF */
  117. extern int    Ambient;
  118. extern int    RANDOMIZE;
  119. extern int    haze;
  120. extern int    transparent[2];
  121. extern int    rotate_lo,rotate_hi;
  122. extern char   busy;
  123. extern float  screenaspect;
  124. extern     double mxmaxfp;
  125. extern     double mxminfp;
  126. extern     double mymaxfp;
  127. extern     double myminfp;
  128. extern     int zdots;        
  129. extern     float originfp;
  130. extern     float depthfp;    
  131. extern     float heightfp;
  132. extern     float widthfp;    
  133. extern     float distfp;    
  134. extern     float eyesfp;    
  135. extern     int neworbittype;
  136. extern     short juli3Dmode;
  137.     
  138. #ifdef XFRACT
  139. extern int decode_fractal_info();
  140. #endif
  141.  
  142. /*
  143.             Save-To-Disk Routines (GIF)
  144.  
  145. GIF and 'Graphics Interchange Format' are trademarks (tm) of Compuserve
  146. Incorporated, an H&R Block Company.
  147.  
  148.  
  149. The following routines perform the GIF encoding when the 's' key is pressed.
  150. The routines refer to several variables that are declared elsewhere
  151. [colors, xdots, ydots, and 'dacbox'], and rely on external routines to
  152. actually read and write screen pixels [getcolor(x,y) and putcolor(x,y,color)].
  153. (Writing pixels is just stuffed in here as a sort of visual status report,
  154. and has nothing to do with any GIF function.)    They also rely on the
  155. existence of an externally-defined 64K dataspace and they use the routines
  156. 'toextra()' and 'cmpextra()' to deal with that dataspace (in the same manner
  157. as 'memcpy()' and 'memcmp()' would).   Otherwise, they perform a generic
  158. GIF-encoder function.
  159.  
  160. Note that these routines use small string- and hash-tables, and "flush"
  161. the GIF entries whenever the hash-table gets two-thirds full or the string
  162. table gets full.   They also use the GIF encoding technique of limiting the
  163. encoded string length to a specific size, "adding" a string to the hash table
  164. at that point even if a matching string exists ("adding" is in quotes, because
  165. if a matching string exists we can increment the code counter but safely throw
  166. the duplicate string away, saving both string space and a hash table entry).
  167.  
  168.    This results in relatively good speed and small data space, but at the
  169. expense of compression efficiency (filesize).    These trade-offs could be
  170. adjusted by modifying the #DEFINEd variables below.
  171.  
  172. Note that the 'strlocn' and 'teststring' routines are declared
  173. to be external just so that they can be defined (and the space re-used)
  174. elsewhere.  The actual declarations are in the assembler code.
  175.  
  176. */
  177.  
  178. #define MAXTEST   100        /* maximum single string length */
  179. #define MAXSTRING 64000     /* total space reserved for strings */
  180.                 /* maximum number of strings available */
  181. #define MAXENTRY  5003        /* (a prime number is best for hashing) */
  182.  
  183. #ifndef XFRACT
  184. extern unsigned int strlocn[MAXENTRY];
  185. extern BYTE teststring[MAXTEST];
  186. extern BYTE block[266];   /* GIF-encoded blocks go here */
  187. #else
  188. unsigned int strlocn[10240];
  189. BYTE teststring[MAXTEST];
  190. BYTE block[266];   /* GIF-encoded blocks go here */
  191. #endif
  192.  
  193. static int numsaves = 0;    /* For adjusting 'save-to-disk' filenames */
  194.  
  195. static FILE *out;
  196. static int last_colorbar;
  197. static int save16bit;
  198. static int outcolor1s, outcolor2s;
  199.  
  200. static int lentest, lastentry, numentries, numrealentries;
  201. static unsigned int nextentry;
  202. static int clearcode, endcode;
  203. static unsigned int hashcode;
  204.  
  205. static BYTE blockcount;
  206. static int startbits, codebits, bytecount, bitcount;
  207.  
  208. static char paletteBW[] = {            /* B&W palette */
  209.       0,  0,  0, 63, 63, 63,
  210.     };
  211. static char paletteCGA[] = {            /* 4-color (CGA) palette  */
  212.       0,  0,  0, 21, 63, 63, 63, 21, 63, 63, 63, 63,
  213.     };
  214. static char paletteEGA[] = {            /* 16-color (EGA/CGA) pal */
  215.       0,  0,  0,  0,  0, 42,  0, 42,  0,  0, 42, 42,
  216.      42,  0,  0, 42,  0, 42, 42, 21,  0, 42, 42, 42,
  217.      21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63,
  218.      63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63,
  219.     };
  220.  
  221. void encoder_overlay() { }    /* for restore_active_ovly */
  222.  
  223. int savetodisk(filename)    /* save-to-disk routine */
  224.    char *filename;
  225.    {
  226.    char tmpmsg[41]; /* before openfile in case of overrun */
  227.    char openfile[80], openfiletype[10];
  228.    char tmpfile[80];
  229.    int newfile;
  230.    int i, j, outcolor1, outcolor2, interrupted;
  231.  
  232.    ENTER_OVLY(OVLY_ENCODER);
  233.  
  234. restart:
  235.  
  236.    save16bit = disk16bit;
  237.    if (gif87a_flag) /* not storing non-standard fractal info */
  238.       save16bit = 0;
  239.  
  240.    strcpy(openfile,filename);        /* decode and open the filename */
  241.    strcpy(openfiletype,DEFAULTFRACTALTYPE);/* determine the file extension */
  242.    if (save16bit)
  243.       strcpy(openfiletype,".pot");
  244.    for (i = 0; i < strlen(openfile); i++)
  245.       if (openfile[i] == '.') {
  246.          strcpy(openfiletype,&openfile[i]);
  247.          openfile[i] = 0;
  248.          }
  249.    if (resave_flag != 1)
  250.       updatesavename(filename); /* for next time */
  251.  
  252.    strcat(openfile,openfiletype);
  253.  
  254.    strcpy(tmpfile,openfile);
  255.    if (access(openfile,0) != 0) /* file doesn't exist */
  256.       newfile = 1;
  257.    else { /* file already exists */
  258.       if (overwrite == 0) {
  259.          if (resave_flag == 0)
  260.             goto restart;
  261.          if (started_resaves == 0) { /* first save of a savetime set */
  262.             updatesavename(filename);
  263.             goto restart;
  264.             }
  265.          }
  266.       if (access(openfile,2) != 0) {
  267.          sprintf(tmpmsg,s_cantwrite,openfile);
  268.          stopmsg(0,tmpmsg);
  269.          EXIT_OVLY;
  270.          return -1;
  271.          }
  272.       newfile = 0;
  273.       i = strlen(tmpfile);
  274.       while (--i >= 0 && tmpfile[i] != SLASHC)
  275.          tmpfile[i] = 0;
  276.       strcat(tmpfile,"fractint.tmp");
  277.       }
  278.  
  279.    started_resaves = (resave_flag == 1) ? 1 : 0;
  280.    if (resave_flag == 2) /* final save of savetime set? */
  281.       resave_flag = 0;
  282.  
  283.    if ((out=fopen(tmpfile,"wb")) == NULL) {
  284.       sprintf(tmpmsg,s_cantcreate,tmpfile);
  285.       stopmsg(0,tmpmsg);
  286.       EXIT_OVLY;
  287.       return -1;
  288.       }
  289.  
  290.    if (dotmode == 11) {            /* disk-video */
  291.       char buf[60];
  292.       sprintf(buf,"Saving %s",openfile);
  293.       dvid_status(1,buf);
  294.       }
  295. #ifdef XFRACT
  296.       else {
  297.       putstring(3,0,0,"Saving to:");
  298.       putstring(4,0,0,openfile);
  299.       putstring(5,0,0,"               ");
  300.       }
  301. #endif
  302.  
  303.    busy = 1;
  304.  
  305.    if (debugflag != 200)
  306.       interrupted = encoder();
  307.    else
  308.       interrupted = timer(2,NULL);    /* invoke encoder() via timer */
  309.  
  310.    busy = 0;
  311.  
  312.    fclose(out);
  313.  
  314.    if (interrupted) {
  315.       char buf[200];
  316.       sprintf(buf,"Save of %s interrupted.\nCancel to ",openfile);
  317.       if (newfile)
  318.          strcat(buf,"delete the file,\ncontinue to keep the partial image.");
  319.       else
  320.          strcat(buf,"retain the original file,\ncontinue to replace original with new partial image.");
  321.       interrupted = 1;
  322.       if (stopmsg(2,buf) < 0) {
  323.          interrupted = -1;
  324.          unlink(tmpfile);
  325.          }
  326.       }
  327.  
  328.    if (newfile == 0 && interrupted >= 0) { /* replace the real file */
  329.       unlink(openfile);        /* success assumed since we checked */
  330.       rename(tmpfile,openfile);    /* earlier with access            */
  331.       }
  332.  
  333.    if (dotmode != 11) {            /* supress this on disk-video */
  334.       if (active_system == 0) {        /* no bars in Windows version */
  335.          outcolor1 = outcolor1s;
  336.          outcolor2 = outcolor2s;
  337.          for (j = 0; j <= last_colorbar; j++) {
  338.             if ((j & 4) == 0) {
  339.                if (++outcolor1 >= colors) outcolor1 = 0;
  340.                if (++outcolor2 >= colors) outcolor2 = 0;
  341.                }
  342.             for (i = 0; 250*i < xdots; i++) { /* clear vert status bars */
  343.                putcolor(i,j,getcolor(i,j)^outcolor1);
  344.                putcolor(xdots-1-i,j,getcolor(xdots-1-i,j)^outcolor2);
  345.                }
  346.             }
  347.          }
  348. #ifdef XFRACT
  349.          putstring(5,0,0,"Saving done\n");
  350. #endif
  351.       }
  352.    else                    /* disk-video */
  353.       dvid_status(1,"");
  354.  
  355.    if (interrupted) {
  356.       texttempmsg(" *interrupted* save ");
  357.       if (initbatch == 2 || initbatch == 5) initbatch = 3; /* if batch mode, set error level */
  358.       EXIT_OVLY;
  359.       return -1;
  360.       }
  361.    if (timedsave == 0) {
  362.       buzzer(0);
  363.       if (initbatch == 0) {
  364.          sprintf(tmpmsg," File saved as %s ",openfile);
  365.          texttempmsg(tmpmsg);
  366.          }
  367.       }
  368.    EXIT_OVLY;
  369.    return 0;
  370.    }
  371.  
  372.  
  373. int encoder()
  374. {
  375. int i, ydot, xdot, color, outcolor1, outcolor2;
  376. int width;
  377. int rownum, rowlimit;
  378. unsigned int hashentry;
  379. BYTE bitsperpixel, x;
  380. int entrynum;
  381. struct fractal_info save_info;
  382.  
  383. if(initbatch)            /* flush any impending keystrokes */
  384.    while(keypressed())
  385.       getakey();
  386.  
  387. setup_save_info(&save_info);
  388.  
  389. #ifndef XFRACT
  390. bitsperpixel = 0;            /* calculate bits / pixel */
  391. for (i = colors; i >= 2; i /= 2 )
  392.     bitsperpixel++;
  393.  
  394. startbits = bitsperpixel+1;        /* start coding with this many bits */
  395. if (colors == 2)
  396.     startbits++;            /* B&W Klooge */
  397. #else
  398.     if (colors==2) {
  399.         bitsperpixel = 1;
  400.         startbits = 3;
  401.     } else {
  402.         bitsperpixel = 8;
  403.         startbits = 9;
  404.     }
  405. #endif
  406.  
  407. clearcode = 1 << (startbits - 1);    /* set clear and end codes */
  408. endcode = clearcode+1;
  409.  
  410. outcolor1 = 0;                /* use these colors to show progress */
  411. outcolor2 = 1;                /* (this has nothing to do with GIF) */
  412. if (colors > 2) {
  413.     outcolor1 = 2;
  414.     outcolor2 = 3;
  415.     }
  416. if (((++numsaves) & 1) == 0) {            /* reverse the colors on alt saves */
  417.     i = outcolor1;
  418.     outcolor1 = outcolor2;
  419.     outcolor2 = i;
  420.     }
  421. outcolor1s = outcolor1;
  422. outcolor2s = outcolor2;
  423.  
  424. if (gif87a_flag == 1) {
  425.     if (fwrite("GIF87a",6,1,out) != 1) goto oops;  /* old GIF Signature */
  426. } else {
  427.     if (fwrite("GIF89a",6,1,out) != 1) goto oops;  /* new GIF Signature */
  428. }
  429.  
  430. width = xdots;
  431. rowlimit = ydots;
  432. if (save16bit) {
  433.     /* pot16bit info is stored as:
  434.        file:    double width rows, right side of row is low 8 bits
  435.        diskvid: ydots rows of colors followed by ydots rows of low 8 bits
  436.        decoder: returns (row of color info then row of low 8 bits) * ydots
  437.        */
  438.     rowlimit <<= 1;
  439.     width <<= 1;
  440.     }
  441. if (write2(&width,2,1,out) != 1) goto oops;  /* screen descriptor */
  442. if (write2(&ydots,2,1,out) != 1) goto oops;
  443. x = 128 + ((6-1)<<4) + (bitsperpixel-1); /* color resolution == 6 bits worth */
  444. if (write1(&x,1,1,out) != 1) goto oops;
  445. if (fputc(0,out) != 0) goto oops;    /* background color */
  446. i = 0;
  447. /** PB, changed to always store pixel aspect ratio, some utilities
  448.     have been reported to like it **/
  449. /**
  450. if ( finalaspectratio < screenaspect-0.01
  451.   || finalaspectratio > screenaspect+0.01) {
  452.  **/
  453. if (viewwindow                    /* less than full screen?  */
  454.   && (viewxdots == 0 || viewydots == 0))    /* and we picked the dots? */
  455.    i = ((double)sydots / (double)sxdots) * 64.0/screenaspect - 14.5;
  456. else /* must risk loss of precision if numbers low */
  457.    i = (((double)ydots / (double)xdots) / finalaspectratio) * 64 - 14.5;
  458. if (i < 1)   i = 1;
  459. if (i > 255) i = 255;
  460. if (gif87a_flag) i = 0;    /* for some decoders which can't handle aspect */
  461. if (fputc(i,out) != i) goto oops;    /* pixel aspect ratio */
  462.  
  463. #ifndef XFRACT
  464. if (colors == 256) {            /* write out the 256-color palette */
  465.     if (gotrealdac) {         /* got a DAC - must be a VGA */
  466.         if (!shftwrite((BYTE *)dacbox,colors)) goto oops;
  467. #else
  468. if (colors > 2) {
  469.         if (gotrealdac) {               /* got a DAC - must be a VGA */
  470.                 if (!shftwrite((BYTE *)dacbox,256)) goto oops;
  471. #endif
  472.      } else {            /* uh oh - better fake it */
  473.         for (i = 0; i < 256; i += 16)
  474.             if (!shftwrite((BYTE *)paletteEGA,16)) goto oops;
  475.         }
  476.     }
  477. if (colors == 2) {            /* write out the B&W palette */
  478.     if (!shftwrite((BYTE *)paletteBW,colors)) goto oops;
  479.     }
  480. #ifndef XFRACT
  481. if (colors == 4) {            /* write out the CGA palette */
  482.     if (!shftwrite(paletteCGA,colors))goto oops;
  483.     }
  484. if (colors == 16) {            /* Either EGA or VGA */
  485.     if (gotrealdac) {
  486.         if (!shftwrite((BYTE *)dacbox,colors))goto oops;
  487.         }
  488.      else    {            /* no DAC - must be an EGA */
  489.         if (!shftwrite(paletteEGA,colors))goto oops;
  490.         }
  491.     }
  492. #endif
  493.  
  494. if (fwrite(",",1,1,out) != 1) goto oops;  /* Image Descriptor */
  495. i = 0;
  496. if (write2(&i,2,1,out) != 1) goto oops;
  497. if (write2(&i,2,1,out) != 1) goto oops;
  498. if (write2(&width,2,1,out) != 1) goto oops;
  499. if (write2(&ydots,2,1,out) != 1) goto oops;
  500. if (write1(&i,1,1,out) != 1) goto oops;
  501.  
  502. bitsperpixel = startbits - 1;        /* raster data starts here */
  503. if (write1(&bitsperpixel,1,1,out) != 1) goto oops;
  504.  
  505. codebits = startbits;            /* start encoding */
  506.  
  507. if (!raster(9999)) goto oops;        /* initialize the raster routine */
  508.  
  509. if (!inittable()) goto oops;        /* initialize the LZW tables */
  510.  
  511. for ( rownum = 0; rownum < ydots; rownum++
  512. #ifdef WINFRACT
  513.       , UpdateStatusBox(rownum, ydots)
  514. #endif
  515. ) {  /* scan through the dots */
  516.     for (ydot = rownum; ydot < rowlimit; ydot += ydots) {
  517.     for (xdot = 0; xdot < xdots; xdot++) {
  518.         if (save16bit == 0 || ydot < ydots)
  519.             color = getcolor(xdot,ydot);
  520.         else
  521.             color = readdisk(xdot+sxoffs,ydot+syoffs);
  522.         teststring[0] = ++lentest;
  523.         teststring[lentest] = color;
  524.         if (lentest == 1) {        /* root entry? */
  525.             lastentry = color;
  526.             continue;
  527.             }
  528.         if (lentest == 2)        /* init   the hash code */
  529.             hashcode = 301 * (teststring[1]+1);
  530.         hashcode *= (color + lentest);    /* update the hash code */
  531.         hashentry = ++hashcode % MAXENTRY;
  532.         for( i = 0; i < MAXENTRY; i++) {
  533.             if (++hashentry >= MAXENTRY) hashentry = 0;
  534.             if (cmpextra(strlocn[hashentry]+sizeof(int),
  535.                 (char *)teststring,lentest+1) == 0)
  536.                     break;
  537.             if (strlocn[hashentry] == 0) i = MAXENTRY;
  538.             }
  539.         /* found an entry and string length isn't too bad */
  540.         if (strlocn[hashentry] != 0 && lentest < MAXTEST-1-sizeof(int)) {
  541.             fromextra(strlocn[hashentry],(char *)&entrynum,sizeof(int));
  542.             lastentry = entrynum;
  543.             continue;
  544.             }
  545.         if (!raster(lastentry)) goto oops;    /* write entry */
  546.         numentries++;        /* act like you added one, anyway */
  547.         if (strlocn[hashentry] == 0) {    /* add new string, if any */
  548.             entrynum = numentries+endcode;
  549.             strlocn[hashentry] = nextentry;
  550.             toextra(nextentry, (char *)&entrynum,sizeof(int));
  551.             toextra(nextentry+sizeof(int),
  552.                 (char *)teststring,lentest+1);
  553.             nextentry += lentest+1+sizeof(int);
  554.             numrealentries++;
  555.             }
  556.         teststring[0] = 1;        /* reset current entry */
  557.         teststring[1] = color;
  558.         lentest = 1;
  559.         lastentry = color;
  560.  
  561.         if ((numentries+endcode) == (1<<codebits))
  562.             codebits++;         /* use longer encoding */
  563.  
  564.         if ( numentries + endcode > 4093 ||    /* out of room? */
  565.             numrealentries > (MAXENTRY*2)/3 ||
  566.             nextentry > MAXSTRING-MAXTEST-1-2*sizeof(int)) {
  567.             if (!raster(lastentry)) goto oops;    /* flush & restart */
  568.             if (!inittable()) goto oops;
  569.             }
  570.         }
  571.     if (dotmode != 11            /* supress this on disk-video */
  572.         && active_system == 0        /* and in Windows version     */
  573.         && ydot == rownum) {
  574.         if ((ydot & 4) == 0) {
  575.             if (++outcolor1 >= colors) outcolor1 = 0;
  576.             if (++outcolor2 >= colors) outcolor2 = 0;
  577.             }
  578.         for (i = 0; 250*i < xdots; i++) {    /* display vert status bars */
  579.                             /*   (this is NOT GIF-related)    */
  580.             /* PB Changed following code to xor color, so that
  581.                image can be restored at end and resumed
  582.                putcolor(      i,ydot,outcolor1);
  583.                putcolor(xdots-1-i,ydot,outcolor2);
  584.             */
  585.             putcolor(i,ydot,getcolor(i,ydot)^outcolor1);
  586.             putcolor(xdots-1-i,ydot,getcolor(xdots-1-i,ydot)^outcolor2);
  587.             }
  588.         last_colorbar = ydot;
  589.         }
  590. #ifdef WINFRACT
  591.         keypressed();
  592.         if (OperCancelled)
  593. #else
  594.         if (keypressed())                     /* keyboard hit - bail out */
  595. #endif
  596.         ydot = rownum = 9999;
  597.     }
  598.     }
  599.  
  600. if (!raster(lastentry)) goto oops;    /* tidy up - dump the last code */
  601.  
  602. if (!raster(endcode)) goto oops;    /* finish the map */
  603.  
  604. if (fputc(0,out) != 0) goto oops;    /* raster data ends here */
  605.  
  606. if (gif87a_flag == 0) { /* store non-standard fractal info */
  607.     /* loadfile.c has notes about extension block structure */
  608.     if (ydot >= 9999)
  609.         save_info.calc_status = 0; /* partial save is not resumable */
  610.     save_info.tot_extend_len = 0;
  611.     if (resume_info != NULL && save_info.calc_status == 2) {
  612.         /* resume info block, 002 */
  613.         save_info.tot_extend_len += extend_blk_len(resume_len);
  614.         if (!put_extend_blk(2,resume_len,resume_info))goto oops;
  615.         }
  616.     if (save_info.fractal_type == FORMULA || save_info.fractal_type == FFORMULA)
  617.         save_info.tot_extend_len += store_item_name(FormName);
  618.     if (save_info.fractal_type == LSYSTEM)
  619.         save_info.tot_extend_len += store_item_name(LName);
  620.     if (save_info.fractal_type == IFS || save_info.fractal_type == IFS3D)
  621.         save_info.tot_extend_len += store_item_name(IFSName);
  622.     if (display3d <= 0 && rangeslen) {
  623.         /* ranges block, 004 */
  624.         save_info.tot_extend_len += extend_blk_len(rangeslen*2);
  625. #ifdef XFRACT
  626.         fix_ranges(ranges,rangeslen,0);
  627.         put_extend_blk(4,rangeslen*2,(char far *)ranges);
  628.         fix_ranges(ranges,rangeslen,0);
  629. #else
  630.         if (!put_extend_blk(4,rangeslen*2,(char far *)ranges))
  631.             goto oops;
  632. #endif
  633.         }
  634.  
  635.     /* main and last block, 001 */
  636.     save_info.tot_extend_len += extend_blk_len(FRACTAL_INFO_SIZE);
  637. #ifdef XFRACT
  638.         decode_fractal_info(&save_info,0);
  639. #endif
  640.     if (!put_extend_blk(1,FRACTAL_INFO_SIZE,(char far *)&save_info)) {
  641.         goto oops;
  642.     }
  643.     }
  644.  
  645. if (fwrite(";",1,1,out) != 1) goto oops;          /* GIF Terminator */
  646.  
  647. return ((ydot < 9999) ? 0 : 1);
  648.  
  649. oops:
  650.     {
  651.     fflush(out);
  652.     stopmsg(0,"Error Writing to disk (Disk full?)");
  653.     return 1;
  654.     }
  655. }
  656.  
  657. static int _fastcall shftwrite(BYTE *color,int numcolors)
  658. /* shift IBM colors to GIF */
  659. {
  660. BYTE thiscolor;
  661. int i,j;
  662. for (i = 0; i < numcolors; i++)
  663.     for (j = 0; j < 3; j++) {
  664.         thiscolor = color[3*i+j];
  665.         thiscolor = thiscolor << 2;
  666.         thiscolor += (thiscolor >> 6);
  667.         if (fputc(thiscolor,out) != thiscolor) return(0);
  668.         }
  669. return(1);
  670. }
  671.  
  672. static int inittable()         /* routine to init tables */
  673. {
  674. int i;
  675.  
  676. if (!raster(clearcode)) return(0);    /* signal that table is initialized */
  677.  
  678. numentries = 0;             /* initialize the table */
  679. numrealentries = 0;
  680. nextentry = 1;
  681. lentest = 0;
  682. codebits = startbits;
  683.  
  684. toextra(0,"\0",1);                      /* clear the hash entries */
  685. for (i = 0; i < MAXENTRY; i++)
  686.     strlocn[i] = 0;
  687.  
  688. return(1);
  689. }
  690.  
  691. static int _fastcall raster(code)    /* routine to block and output codes */
  692. unsigned int code;
  693. {
  694. unsigned int icode, i, j;
  695.  
  696. if (code == 9999) {            /* special start-up signal */
  697.     bytecount = 0;
  698.     bitcount = 0;
  699.     for (i = 0; i < 266; i++)
  700.         block[i] = 0;
  701.     return(1);
  702.     }
  703.  
  704. icode = code << bitcount;        /* update the bit string */
  705. block[bytecount  ] |= (icode & 255);
  706. block[bytecount+1] |= ((icode>>8) & 255);
  707. icode = (code>>8) << bitcount;
  708. block[bytecount+2] |= ((icode>>8) & 255);
  709. bitcount += codebits;
  710. while (bitcount >= 8) {         /* locate next starting point */
  711.     bitcount -= 8;
  712.     bytecount++;
  713.     }
  714.  
  715. if (bytecount > 250 || code == endcode) {    /* time to write a block */
  716.     if (code == endcode)
  717.         while (bitcount > 0) {        /* if EOF, find the real end */
  718.             bitcount -= 8;
  719.             bytecount++;
  720.             }
  721.     i = bytecount;
  722.     blockcount = i;
  723.         if (write1(&blockcount,1,1,out) != 1) return(0); /* write the block */
  724.     if (fwrite(block,i,1,out) != 1) return(0);
  725.     bytecount = 0;                /* now re-start the block */
  726.     for (j = 0; j < 5; j++)         /* (may have leftover bits) */
  727.         block[j] = block[j+i];
  728.     for (j = 5; j < 266; j++)
  729.         block[j] = 0;
  730.     }
  731. return(1);
  732. }
  733.  
  734.  
  735. static int _fastcall extend_blk_len(int datalen)
  736. {
  737.    return(datalen + (datalen+254)/255 + 15);
  738.    /*       data   +    1.per.block   + 14 for id + 1 for null at end  */
  739. }
  740.  
  741. static int _fastcall put_extend_blk(int block_id,int block_len,char far *block_data)
  742. {
  743.    int i,j;
  744.    char header[15];
  745.    strcpy(header,"!\377\013fractint");
  746.    sprintf(&header[11],"%03u",block_id);
  747.    if (fwrite(header,14,1,out) != 1) return(0);
  748.    i = (block_len + 254) / 255;
  749.    while (--i >= 0) {
  750.       block_len -= (j = min(block_len,255));
  751.       if (fputc(j,out) != j) return(0);
  752.       while (--j >= 0)
  753.      fputc(*(block_data++),out);
  754.       }
  755.    if (fputc(0,out) != 0) return(0);
  756.    return(1);
  757. }
  758.  
  759. static int _fastcall store_item_name(char *nameptr)
  760. {
  761.    char tmpname[40];
  762.    strcpy(tmpname,nameptr);
  763.    /* formula/lsys/ifs info block, 003 */
  764.    put_extend_blk(3,40,tmpname);
  765.    return(extend_blk_len(40));
  766. }
  767.  
  768. static void _fastcall setup_save_info(struct fractal_info *save_info)
  769. {
  770.    int i;
  771.  
  772.    if(fractype != FORMULA && fractype != FFORMULA)
  773.       maxfn = 0;     
  774.    /* set save parameters in save structure */
  775.    strcpy(save_info->info_id, INFO_ID);
  776.    save_info->version          = 9; /* file version, independant of system */
  777.    save_info->iterations      = maxit;
  778.    save_info->fractal_type    = fractype;
  779.    save_info->xmin          = xxmin;
  780.    save_info->xmax          = xxmax;
  781.    save_info->ymin          = yymin;
  782.    save_info->ymax          = yymax;
  783.    save_info->creal          = param[0];
  784.    save_info->cimag          = param[1];
  785.    save_info->videomodeax     = videoentry.videomodeax;
  786.    save_info->videomodebx     = videoentry.videomodebx;
  787.    save_info->videomodecx     = videoentry.videomodecx;
  788.    save_info->videomodedx     = videoentry.videomodedx;
  789.    save_info->dotmode          = videoentry.dotmode % 100;
  790.    save_info->xdots          = videoentry.xdots;
  791.    save_info->ydots          = videoentry.ydots;
  792.    save_info->colors          = videoentry.colors;
  793.    save_info->parm3          = 0; /* pre version==7 fields */
  794.    save_info->parm4          = 0;
  795.    save_info->dparm3          = param[2];
  796.    save_info->dparm4          = param[3];
  797.    save_info->dparm5          = param[4];
  798.    save_info->dparm6          = param[5];
  799.    save_info->dparm7          = param[6];
  800.    save_info->dparm8          = param[7];
  801.    save_info->dparm9          = param[8];
  802.    save_info->dparm10         = param[9];
  803.    save_info->fillcolor          = fillcolor;
  804.    save_info->potential[0]    = potparam[0];
  805.    save_info->potential[1]    = potparam[1];
  806.    save_info->potential[2]    = potparam[2];
  807.    save_info->rflag          = rflag;
  808.    save_info->rseed          = rseed;
  809.    save_info->inside          = inside;
  810.    save_info->logmap          = LogFlag;
  811.    save_info->invert[0]       = inversion[0];
  812.    save_info->invert[1]       = inversion[1];
  813.    save_info->invert[2]       = inversion[2];
  814.    save_info->decomp[0]       = decomp[0];
  815.    save_info->biomorph          = usr_biomorph;
  816.    save_info->symmetry          = forcesymmetry;
  817.    for (i = 0; i < 16; i++)
  818.       save_info->init3d[i] = init3d[i];
  819.    save_info->previewfactor   = previewfactor;
  820.    save_info->xtrans          = xtrans;
  821.    save_info->ytrans          = ytrans;
  822.    save_info->red_crop_left   = red_crop_left;
  823.    save_info->red_crop_right  = red_crop_right;
  824.    save_info->blue_crop_left  = blue_crop_left;
  825.    save_info->blue_crop_right = blue_crop_right;
  826.    save_info->red_bright      = red_bright;
  827.    save_info->blue_bright     = blue_bright;
  828.    save_info->xadjust          = xadjust;
  829.    save_info->eyeseparation   = eyeseparation;
  830.    save_info->glassestype     = glassestype;
  831.    save_info->outside          = outside;
  832.    save_info->x3rd          = xx3rd;
  833.    save_info->y3rd          = yy3rd;
  834.    save_info->calc_status     = calc_status;
  835.    save_info->stdcalcmode     = stdcalcmode;
  836.    save_info->distest          = distest;
  837.    save_info->floatflag       = floatflag;
  838.    save_info->bailout          = bailout;
  839.    save_info->calctime          = calctime;
  840.    save_info->trigndx[0]      = trigndx[0];
  841.    save_info->trigndx[1]      = trigndx[1];
  842.    save_info->trigndx[2]      = trigndx[2];
  843.    save_info->trigndx[3]      = trigndx[3];
  844.    save_info->finattract      = finattract;
  845.    save_info->initorbit[0]    = initorbit.x;
  846.    save_info->initorbit[1]    = initorbit.y;
  847.    save_info->useinitorbit    = useinitorbit;
  848.    save_info->periodicity     = periodicitycheck;
  849.    save_info->pot16bit          = disk16bit;
  850.    save_info->faspectratio    = finalaspectratio;
  851.    save_info->system          = save_system;
  852.    save_info->release          = save_release;
  853.    save_info->flag3d          = display3d;
  854.    save_info->ambient          = Ambient;
  855.    save_info->randomize       = RANDOMIZE;
  856.    save_info->haze          = haze;
  857.    save_info->transparent[0]  = transparent[0];
  858.    save_info->transparent[1]  = transparent[1];
  859.    save_info->rotate_lo       = rotate_lo;
  860.    save_info->rotate_hi       = rotate_hi;
  861.    save_info->distestwidth    = distestwidth;
  862.    save_info->mxmaxfp         = mxmaxfp;
  863.    save_info->mxminfp         = mxminfp;
  864.    save_info->mymaxfp         = mymaxfp;
  865.    save_info->myminfp         = myminfp;
  866.    save_info->zdots           = zdots;        
  867.    save_info->originfp        = originfp;
  868.    save_info->depthfp         = depthfp;    
  869.    save_info->heightfp        = heightfp;
  870.    save_info->widthfp         = widthfp;    
  871.    save_info->distfp          = distfp;    
  872.    save_info->eyesfp          = eyesfp;    
  873.    save_info->orbittype       = neworbittype;
  874.    save_info->juli3Dmode      = juli3Dmode;
  875.    save_info->maxfn           = maxfn;
  876.    save_info->inversejulia    = (major_method << 8) + minor_method; /* MVS */
  877.    for (i = 0; i < sizeof(save_info->future)/sizeof(short); i++)
  878.       save_info->future[i] = 0;
  879. }
  880.